package pub.cleangao.mybatis.expression;

import lombok.Getter;
import pub.cleangao.common.util.StringUtil;
import pub.cleangao.mybatis.dao.Sort;
import java.util.*;


@Getter
public class Expressions {

    public static Expressions lambda() {
        return new Expressions();
    }

    // where expression
    private final List<WhereExpression> whereExpressionList = new ArrayList<>();
    // order by
    private boolean hasOrderBy = false;
    private final Map<String, Sort> orderBy = new LinkedHashMap<>();
    // limit
    private boolean hasLimit = false;
    private String limitSql = "";
    private long offset = 0L;
    private int pageSize = 35;
    // last sql
    private boolean hasLastSql = false;
    private String lastSql = "";

    //------------------------------------ build expression ------------------------------------

    public Expressions eq(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.eq, value, whereExpressionList.size()));
        return this;
    }

    public Expressions orEq(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.eq, value, whereExpressionList.size()));
        return this;
    }

    public Expressions notEq(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.notEq, value, whereExpressionList.size()));
        return this;
    }

    public Expressions orNotEq(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.notEq, value, whereExpressionList.size()));
        return this;
    }

    public Expressions gt(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.gt, value, whereExpressionList.size()));
        return this;
    }

    public Expressions orGt(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.gt, value, whereExpressionList.size()));
        return this;
    }

    public Expressions ge(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.ge, value, whereExpressionList.size()));
        return this;
    }

    public Expressions orGe(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.ge, value, whereExpressionList.size()));
        return this;
    }

    public Expressions lt(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.lt, value, whereExpressionList.size()));
        return this;
    }

    public Expressions orLt(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.lt, value, whereExpressionList.size()));
        return this;
    }

    public Expressions le(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.le, value, whereExpressionList.size()));
        return this;
    }

    public Expressions orLe(String columnName, Object value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.le, value, whereExpressionList.size()));
        return this;
    }

    public Expressions like(String columnName, String value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.like, value, whereExpressionList.size()));
        return this;
    }

    public Expressions orLike(String columnName, String value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.like, value, whereExpressionList.size()));
        return this;
    }

    public Expressions in(String columnName, Collection<?> value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.in, value, whereExpressionList.size()));
        return this;
    }

    public Expressions orIn(String columnName, Collection<?> value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.in, value, whereExpressionList.size()));
        return this;
    }

    public Expressions in(String columnName, Object[] value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.in, value, whereExpressionList.size()));
        return this;
    }

    public Expressions orIn(String columnName, Object[] value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.in, value, whereExpressionList.size()));
        return this;
    }

    public Expressions notIn(String columnName, Collection<?> value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.notIn, value, whereExpressionList.size()));
        return this;
    }

    public Expressions orNotIn(String columnName, Collection<?> value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.notIn, value, whereExpressionList.size()));
        return this;
    }

    public Expressions notIn(String columnName, Object[] value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.notIn, value, whereExpressionList.size()));
        return this;
    }

    public Expressions orNotIn(String columnName, Object[] value) {
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.notIn, value, whereExpressionList.size()));
        return this;
    }

    public Expressions between(String columnName, Object startValue, Object endValue) {
        whereExpressionList.add(BetweenExpression.buildExpression(WhereJoint.AND, columnName, startValue, endValue, whereExpressionList.size()));
        return this;
    }

    public Expressions orBetween(String columnName, Object startValue, Object endValue) {
        whereExpressionList.add(BetweenExpression.buildExpression(WhereJoint.OR, columnName, startValue, endValue, whereExpressionList.size()));
        return this;
    }

    public Expressions isNull(String columnName) {
        whereExpressionList.add(NullExpression.buildExpression(WhereJoint.AND, columnName, true, whereExpressionList.size()));
        return this;
    }

    public Expressions orIsNull(String columnName) {
        whereExpressionList.add(NullExpression.buildExpression(WhereJoint.OR, columnName, true, whereExpressionList.size()));
        return this;
    }

    public Expressions isNotNull(String columnName) {
        whereExpressionList.add(NullExpression.buildExpression(WhereJoint.AND, columnName, false, whereExpressionList.size()));
        return this;
    }

    public Expressions orIsNotNull(String columnName) {
        whereExpressionList.add(NullExpression.buildExpression(WhereJoint.OR, columnName, false, whereExpressionList.size()));
        return this;
    }

    public Expressions isEmpty(String columnName) {
        whereExpressionList.add(NullExpression.buildExpression(WhereJoint.AND, columnName, true, whereExpressionList.size()));
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.eq, SqlLiteral.EMPTY, whereExpressionList.size()));
        return this;
    }

    public Expressions orIsEmpty(String columnName) {
        whereExpressionList.add(NullExpression.buildExpression(WhereJoint.OR, columnName, true, whereExpressionList.size()));
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.OR, columnName, WhereOperator.eq, SqlLiteral.EMPTY, whereExpressionList.size()));
        return this;
    }

    public Expressions isNotEmpty(String columnName) {
        whereExpressionList.add(NullExpression.buildExpression(WhereJoint.AND, columnName, false, whereExpressionList.size()));
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.notEq, SqlLiteral.EMPTY, whereExpressionList.size()));
        return this;
    }

    public Expressions orIsNotEmpty(String columnName) {
        whereExpressionList.add(NullExpression.buildExpression(WhereJoint.OR, columnName, false, whereExpressionList.size()));
        whereExpressionList.add(ValueExpression.buildExpression(WhereJoint.AND, columnName, WhereOperator.notEq, SqlLiteral.EMPTY, whereExpressionList.size()));
        return this;
    }

    public Expressions orderBy(String columnName, Sort sort) {
        orderBy.put(columnName, sort);
        this.hasOrderBy = true;
        return this;
    }


    public Expressions lastSql(String sql) {
        if (StringUtil.hasText(sql)) {
            this.lastSql = sql;
        }
        this.hasLastSql = true;
        return this;
    }


    public Expressions limit(long offset, int... pageSize) {
        if (pageSize != null && pageSize.length > 0) {
            this.limitSql = SqlLiteral.LIMIT + offset + SqlLiteral.COMMA + pageSize[0];
            this.pageSize = pageSize[0];
        } else {
            this.limitSql = SqlLiteral.LIMIT + offset;
        }
        this.offset = offset;
        this.hasLimit = true;
        return this;
    }



}
